﻿using System;
using System.Threading.Tasks;
using AntJoin.Redis;
using AntJoin.SignalR.Models;
using Microsoft.AspNetCore.SignalR;

namespace AntJoin.SignalR.Hubs
{
    public abstract class BaseHub<T> : Hub<T>, IHubServer where T : class, IHubClient
    {
        /// <summary>
        /// 连接的时候
        /// </summary>
        /// <returns></returns>
        public override Task OnConnectedAsync()
        {
            var connectionId = Context.ConnectionId;
            var userId = GetUserId(Context);
            if (!string.IsNullOrEmpty(userId))
                Login(userId, connectionId);
            return base.OnConnectedAsync();
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <returns></returns>
        public override Task OnDisconnectedAsync(Exception exception)
        {
            var connectionId = Context.ConnectionId;
            var userId = GetUserId(Context);
            if (!string.IsNullOrEmpty(userId))
                Logout(userId, connectionId);
            return base.OnDisconnectedAsync(exception);
        }


        /// <summary>
        /// 发送消息给单人
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public virtual async Task SendMessage(long userId, BaseHubMessage message)
        {
            await Clients.User(GetConnectionId(userId)).ReceiveMessage(message);
        }


        /// <summary>
        /// 加入群组
        /// </summary>
        /// <param name="groupName"></param>
        /// <returns></returns>
        public virtual async Task JoinGroup(string groupName)
        {
            var connectionId = Context.ConnectionId;
            await Groups.AddToGroupAsync(connectionId, groupName);
        }


        /// <summary>
        /// 离开群组
        /// </summary>
        /// <param name="groupName"></param>
        /// <returns></returns>
        public virtual async Task LeavingGroup(string groupName)
        {
            var connectionId = Context.ConnectionId;
            await Groups.RemoveFromGroupAsync(connectionId, groupName);
        }


        /// <summary>
        /// 发送消息给群组
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public virtual async Task SendGroupMessage(string groupName, BaseHubMessage message)
        {
            await Clients.Group(groupName).ReceiveGroupMessages(message);
        }


        /// <summary>
        /// 广播信息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public virtual async Task SendAllMessage(BaseHubMessage message)
        {
            await Clients.All.ReceiveAllMessages(message);
        }


        /// <summary>
        /// 获取用户ID
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected string GetUserId(HubCallerContext context)
        {
            return context.User?.Identity?.Name ?? context.GetHttpContext().Request.Query["userid"].ToString();
        }

        protected BaseHub()
        {
            var name = GetType().Name;
            _userKeyPrev = "SignalR:" + name + ":UserId:";
            _connectKeyPrev = "SignalR:" + name + ":ConnectionId:";
        }
        #region 管理用户连接
        //2个都存，方便根据ConnectionId查找到对应的UserId
        private readonly string _userKeyPrev;
        private readonly string _connectKeyPrev;

        /// <summary>
        /// 登录，保存用户数据
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="connectionId"></param>
        private void Login(string userId, string connectionId)
        {
            RedisHelper.SetValue(_userKeyPrev + userId, connectionId);
            RedisHelper.SetValue(_connectKeyPrev + connectionId, userId);
        }


        /// <summary>
        /// 登录，保存用户数据
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="connectionId"></param>
        private void Logout(string userId, string connectionId)
        {
            if (string.IsNullOrEmpty(userId))
                userId = RedisHelper.GetValue(_connectKeyPrev + connectionId);
            RedisHelper.DelKey(_connectKeyPrev + connectionId);
            RedisHelper.DelKey(_userKeyPrev + userId);
        }


        /// <summary>
        /// 根据UserId获取连接id
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        private string GetConnectionId(long userId)
        {
            return RedisHelper.GetValue(_userKeyPrev + userId);
        }
        #endregion
    }
}
